Earth Engine workshop exercises

Can we simplify this script?

Exercise: Instead of returning a FeatureCollection of sampledPoints around each buffered point, modify the samplePoints function so that it:

  1. Takes the mean of all the samplePoints within a bufferzone using the same “reduceColumns” method I showed you earlier.

  2. Creates a feature with a null geometry and the bufferzone mean assigned to the buffered point ID from which the points were sampled.

  3. Uses this new function and a mapping operation to create the meanPopDensFC variable without needing to compute sampledPoints, meanPopDens, or meanPopDensList.

time:30 minutes

Modified samplePoints function

// Function to sample random points within each buffered area
var samplePoints = function (feature) {
  var geometry = feature.geometry();
  var randomPoints = ee.FeatureCollection.randomPoints(geometry, 10);
  var sampledPoints = popDensYearBuffered.sampleRegions({
    collection: randomPoints,
    scale: 1000,
    tileScale: 16
  })
  // Add the buffered area ID to each sampled point
  sampledPoints = sampledPoints.map(function(point) {
    return point.set('BufferedAreaID', feature.get('ID'));
  });

  // Calculate the mean 'population_density' for each group
  var meanPopDens = sampledPoints.reduceColumns({
    reducer: ee.Reducer.mean(),
    selectors: ['population_density']
  });
  return ee.Feature(null, {
    'BufferedAreaID': feature.get('ID'),
    'mean': meanPopDens.get('mean')
  });
};

// Sample 10 random points within each buffered area and calculate the mean population density
var meanPopDensFC = bufferedPoints.map(samplePoints);

Can we get rid of needing to assign ID’s?

If we take the mean inside of samplePoints we could also do the filtering inside the function and return geometries without needing to access a bufferedPoint’s ID.

Exercise:

Modify the “samplePoints” function so that it: 1. doesn’t need to assign an “ID” value to “BufferedAreaID”. 2. Filters out mean population density values less than 100 people per sq. km. 3. returns a “highDensityPoint” candidate directly.

time: 30 minutes

Further modified sample points function

// Function to sample random points within each buffered area
var samplePoints = function (feature) {
  var geometry = feature.geometry();
  var randomPoints = ee.FeatureCollection.randomPoints(geometry, 10);
  var sampledPoints = popDensYearBuffered.sampleRegions({
    collection: randomPoints,
    scale: 1000,
    tileScale: 16
  })

  // Calculate the mean 'population_density' for each group
  var meanPopDens = sampledPoints.reduceColumns({
    reducer: ee.Reducer.mean(),
    selectors: ['population_density']
  });

  // Filter out mean population density values 
  // less than 100 people per sq. km.
  var mean = meanPopDens.get('mean');
  if (mean < 100) {
    return null;
  }

  // return a "highDensityPoint" candidate
  return ee.Feature(geometry, {
    'mean': mean
  });
};

// Map highDensityPoints to get candidate points
var highDensityPoints = bufferedPoints.map(samplePoints)

Stripping out ID assignment from rest of script

Exercise

Remove ID assignment from 1st part of the script by:

  1. Rename the “bufferAndSetID” function to just “bufferPoint”.

  2. Modify this new “bufferPoint” function so that it takes in a point feature instead of an index and then just buffers this point instead of both buffering and doing index assignment.

  3. Map this new function over the intersectionPoints featureCollection to get a new “bufferedPoints” featureCollection that doesn’t have id’s.

time: 20 minutes

Seperating out functions

Another way to simplify might be to create a new module to store functions we have created in this script.

Exercise:

  • Create an additional file called “Helpers”.
  • Then use the “Docs” tab in the lefthand pane to research how to include this file’s exported functions into your port finding script.

time: 10 minutes

How to include your helper module

To include this module we will add the following line to the beginning of our port finding script:


// Import the lineToPoint function
var hlp = require('users/dylanblee/REUworkshop:Helpers');

Put the lineToPoint function into your helper module

Exercise:

  • Research how to export a function from a javascript script.
  • Migrate the “lineToPoint” function from port finder script to helper module.
  • Call lineToPoint from helper module in your modified script instead of from the main script.

time: 20 minutes

lineToPoint in the helper module

Here is what we added to the helper module:

exports.lineToPoint = function(feature) {
  // Get the geometry
  var geom = feature.geometry();
  // Get the centroid of the geometry
  var centroid = geom.centroid();
  // Create a new point feature
  var pointFeature = ee.Feature(centroid, feature.toDictionary());
  return pointFeature;
};
and here is how we call this function from the helper module:
// Apply the lineToPoint function to each element
// in intersectionPoints
var intersectionPoints = selectedLines.map(hlp.lineToPoint);

modularizing bufferAndSetID

We would also like to put other functions we have created. For example, “bufferAndSetID”. What stops us from doing the same thing we did with “lineToPoint”?

Exercise:

Try putting bufferAndSetID into your helper module and see what happens.

time: 15 minutes

Why we can’t seperate the bufferAndSetID function as-is

We currently can’t put bufferAndSetID into a seperate function because it relies on a variable defined earlier in the script, pointsList.

modularizing bufferAndSetID

So we need to modify bufferAndSetID so that it doesn’t rely on a variable defined earlier in the script.

Exercise:

  1. Modify the “bufferAndSetID” function so that it takes in a single point feature as well as an ID index.
  2. Put the rewritten “bufferAndSetID” function into your helper module.